﻿--[[
   @brief    QOS file downloader
   @author   jameszhai
   @version  1.0
   @date     2017-03-20
--]]

TOssTask =
{
    sFile = nil;
    sJson = nil;
};

function TOssTask:new(sTemp, bCache)
    local     pObjt = {sFile=sTemp, bCache=false, zSink={}};

    setmetatable(pObjt, self);
    self.__index = self;

    return pObjt;
end;

function TOssTask:AddSink(sSink)
    for nIdx = 1,#self.zSink do
        if (sSink == self.zSink[nIdx]) then
            return true;
        end;
    end;

    table.insert(self.zSink, sSink);
    return true;
end;

function TOssTask:DoCallBack(zData)
    TOssTask.sFile = self.sFile;
    TOssTask.sJson = zData;

    for nIdx = 1, #self.zSink do
        local sCode = self.zSink[nIdx] .. "(TOssTask.sFile, TOssTask.sJson);";
        local pCode = loadstring(sCode);

        if (nil ~= pCode) then
            pCode();
        end;
    end;

    TOssTask.zTemp = nil;
end;

function TOssTask:IsSame(sTemp)
    if (self.sFile == sTemp) then
        return true;
    else
        return false;
    end;
end;

function TOssTask:GetFile()
    return self.sFile;
end;

function TOssTask:NeedCache()
    return self.bCache;
end;

-- 配置文件
EOssConfig = 
{
    sOssUrl = LoadStr("OSS_CONFIG_URL"); 
};

-- OSS配置
TOssConfig = 
{
    InitConfig = function()
        comm_center.reg_service("Svr_GetOssCfg", "TOssConfig.OnGetOssCfg")
    end;

    -- 获取OSS配置
    OnGetOssCfg = function(zParam)
        TOssConfig.QueryCfg(zParam["file"], zParam["sink"], zParam["cache"]);
    end;

    -- 回调
    DoCallBack = function(sSink, sFile, sJson)
        TOssConfig.sCurFile = sFile;
        TOssConfig.sCurJson = sJson;

        local   sCode = sSink .. "(TOssConfig.sCurFile, TOssConfig.sCurJson)";
        local   pCode = loadstring(sCode);

        if (nil ~= pCode) then
            pCode();
        end;
    end;

    -- 添加回调
    AddSink = function(sFile, sSink)
        if (nil ~= TOssConfig.zCurTask) and TOssConfig.zCurTask:IsSame(sFile) then
            TOssConfig.zCurTask:AddSink(sSink);
            return true;
        end;

        local     pTask = nil;
        if TOssConfig.zWaitLst.first <= TOssConfig.zWaitLst.last then
            for i = TOssConfig.zWaitLst.first, TOssConfig.zWaitLst.last do
                if TOssConfig.zWaitLst[i] ~= nil and TOssConfig.zWaitLst[i].sFile == sFile then
                    pTask = TOssConfig.zWaitLst[i];
                end
            end;
        end;

        if (nil ~= pTask) then
            pTask:AddSink(sSink);
            return true;
        else
            return false;
        end;
    end;

    -- 请求配置
    QueryCfg = function(sFile, sSink, bCache)
        -- 在缓存的配置表中查找
        if nil ~= TOssConfig.zCfgList[sFile] then
            TGPLog.LogI("OssCfgM", "Get config from cache.");
            TOssConfig.DoCallBack(sSink, sFile, TOssConfig.zCfgList[sFile]);
            return;
        end;

        if TOssConfig.AddSink(sFile, sSink) then
            TGPLog.LogI("OssCfgM", "Repeat query same config.");
        else
            local     zTask = TOssTask:new(sFile, bCache);

            zTask:AddSink(sSink);

            -- 添加到等待列表中
            if TOssConfig.bIsQuery then
                local last = TOssConfig.zWaitLst.last + 1;
                TOssConfig.zWaitLst.last = last;
                TOssConfig.zWaitLst[last] = zTask;
            else    -- 获取配置
                TOssConfig.GetOssCfg(zTask);
            end;
        end;
    end;

    -- 请求OSS配置文件
    GetOssCfg = function(zTask)
        local   zPost = {};
        local   sUrl  = EOssConfig.sOssUrl .. zTask:GetFile();

        TOssConfig.zCurTask = zTask;

        if (base_utility.curl_request_async(sUrl, 
            "TOssConfig.OnNetResult", true, zPost)) then
            TOssConfig.bIsQuery = true;
            TGPLog.LogD("OSSCfgM", "Query BG image config.");
        else
            TOssConfig.NotifyResult(nil);
            TGPLog.LogI("OSSCfgM", "Curl request fail.");
        end;
    end;

    --
    -- 以下为内部接口
    --
    OnNetResult = function(sResult)
        TOssConfig.bIsQuery = false;

        if (nil ~= sResult) and ("" ~= sResult) then
            --[[var CommCfg = 
                {"data_version": "0", 
                  "update_time": "1476266199", 
                  "data":
                  [
                    {
                      "item_id": "1",
                      "item_update_time": "2016-10-12 17:56:39",
                      "data0": "123456",
                      "data1": "123456"
                    }
                  ]
                };
            ]]
            local   nFstIdx = string.find(sResult, "{");
            
            if (nil == nFstIdx) then
                TOssConfig.NotifyResult(nil);
                TGPLog.LogI("OssCfgM", "Parser config fail[{].");
                return  false;
            end;
            
            local   nLstIdx = nil;  -- string.find(sJson, "}", -1, -2); 有问题，先自己实现一个

            for nIdx = #sResult, 1, -1 do
                if 125 == string.byte(sResult, nIdx) then -- "}"
                    nLstIdx = nIdx;
                    break;
                end;
            end;

            if (nil == nLstIdx) then
                TOssConfig.NotifyResult(nil);
                TGPLog.LogI("OssCfgM", "Parser config fail[}].");
                return  false;
            end;

            local   sTemp = string.sub(sResult, nFstIdx, nLstIdx);
            local   zData = base_utility.json_to_table(sTemp);

            if nil ~= zData then
                TOssConfig.NotifyResult(zData);
            else
                TOssConfig.NotifyResult(nil);
            end;
        else
            TOssConfig.NotifyResult(nil);
            TGPLog.LogI("OSSCfgM", "Net download fail.");
        end;

        TOssConfig.QueryNext();
    end;

    -- 回调
    DoCallBack = function(sJson)
        if nil ~= TOssConfig.zCurTask then
            TOssConfig.zCurTask:DoCallBack(sJson);
        end;
    end;

    -- 通知结果
    NotifyResult = function(sJson)
        if nil ~= TOssConfig.zCurTask then
            -- 数据回调
            TOssConfig.DoCallBack(sJson);

            -- 缓存数据
            if TOssConfig.zCurTask:NeedCache() and (nil ~= sJson) and 
               (nil ~= TOssConfig.zCurTask:GetFile()) then
                TOssConfig.zCfgList[TOssConfig.zCurTask:GetFile()] = sJson;
            end;

            -- 清空本次数据
            TOssConfig.zCurTask = nil;
        end;
    end;

    -- 请求下一个
    QueryNext = function()
        local first = TOssConfig.zWaitLst.first;
        if (nil ~= TOssConfig.zWaitLst) and (first <= TOssConfig.zWaitLst.last) then
            TOssConfig.zCurTask = TOssConfig.zWaitLst[first];
            TOssConfig.zWaitLst[first] = nil;
            TOssConfig.zWaitLst.first = TOssConfig.zWaitLst.first + 1;
            TOssConfig.GetOssCfg(TOssConfig.zCurTask);
        end;
    end;

    -- local
    zWaitLst = {first = 1, last = 0};      -- 当前的配置缓存
    zCurTask = nil;     -- 当前的任务
    zCfgList = {};      -- 缓存配置
    bIsQuery = false;   -- 是否在请求中

    -- 数据
    sCurFile = nil;
    sCurJson = nil;

};